package com.haiyuancloud.auth.service.impl;

import com.baidu.fsg.uid.impl.CachedUidGenerator;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.haiyuancloud.auth._enum.SysDsEnum;
import com.haiyuancloud.auth.model.SysDsModel;
import com.haiyuancloud.auth.model.SysTenantModel;
import com.haiyuancloud.auth.service.TbLogLoginService;
import com.haiyuancloud.common.core.entity.HaiyuanAuthUser;
import com.haiyuancloud.common.core.entity.constant.HaiyuanConstant;
import com.haiyuancloud.common.core.entity.constant.ParamsConstant;
import com.haiyuancloud.common.core.entity.constant.SocialConstant;
import com.haiyuancloud.common.core.entity.constant.StringConstant;
import com.haiyuancloud.common.core.entity.system.*;
import com.haiyuancloud.common.core.utils.HaiyuanUtil;
import com.alibaba.fastjson.JSON;
import com.haiyuancloud.auth.mapper.*;
import com.haiyuancloud.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author haiyuan
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class HaiyuanUserDetailServiceImpl implements UserDetailsService {

    @Resource
    private CachedUidGenerator uidGenerator;

    @Resource
    private TbLogLoginService tbLogLoginService;

    private final PasswordEncoder passwordEncoder;

    private final TbOrgStaffMapper tbOrgStaffMapper;

    private final TbOrgDeptStaffMapper tbOrgDeptStaffMapper;

    private final TbOrgDomainMapper tbOrgDomainMapper;

    private final TbOrgDeptMapper tbOrgDeptMapper;

    private final TbOrgRoleStaffMapper tbOrgRoleStaffMapper;

    private final TbOrgRoleMenuMapper tbOrgRoleMenuMapper;

    private final TbOrgMenuMapper tbOrgMenuMapper;

    private final TbOrgPostStaffMapper tbOrgPostStaffMapper;

    private final TbOrgJobStaffMapper tbOrgJobStaffMapper;

    private final TbSysTenantMapper tbSysTenantMapper;

    private final TbSysTenantRefDsMapper tbSysTenantRefDsMapper;

    private final TbSysTenantUserMapper tbSysTenantUserMapper;

    private final TbSysTenantProductMapper tbSysTenantProductMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("加载用户名loadUserByUsername:"+username);
        SysTenantModel sysTenantModel = new SysTenantModel();
        HttpServletRequest httpServletRequest = HaiyuanUtil.getHttpServletRequest();
        String productId = ObjectUtil.toString(httpServletRequest.getParameter("productId"),HaiyuanConstant.S_PRODUCT_ID);
        String layoutId = ObjectUtil.toString(httpServletRequest.getParameter("layoutId"),HaiyuanConstant.I_LAYOUT_ID);
        this.getSysDsModel(username,sysTenantModel);
        SysDsModel sysDsModel = sysTenantModel.getSysDsModel();
        if(ObjectUtil.isNull(sysDsModel)){
            insertFailue ("master",username,2, "账号不存在.");
            throw new UsernameNotFoundException(username);
        }

        List<TbSysTenantProduct> tbSysTenantProductList =tbSysTenantProductMapper.findProductListByTenantId(sysTenantModel.getTENANT_ID());
        List<String> productIdList = tbSysTenantProductList.stream().map(TbSysTenantProduct::getSProductId).map(s ->String.valueOf(s)).collect(Collectors.toList());

        DynamicDataSourceContextHolder.push(sysDsModel.getOrg());
        TbOrgStaff tbOrgStaff = tbOrgStaffMapper.findByAcc(username);
        if (tbOrgStaff != null) {

            List<TbOrgDeptStaff> orgDeptFollowStaffList = tbOrgDeptStaffMapper.findDeptListByLeaderId(tbOrgStaff.getIStaffId());
            String followStaffId = orgDeptFollowStaffList.stream().map(TbOrgDeptStaff::getIStaffId).map(s ->String.valueOf(s)).collect(Collectors.joining(StringConstant.COMMA));
            String followStaffName = orgDeptFollowStaffList.stream().map(TbOrgDeptStaff::getSStaffName).collect(Collectors.joining(StringConstant.COMMA));


            List<TbOrgDeptStaff> orgDeptStaffList = tbOrgDeptStaffMapper.findDeptListByStaffId(tbOrgStaff.getIStaffId());
            String orgDeptId = orgDeptStaffList.stream().map(TbOrgDeptStaff::getIDeptId).map(s ->String.valueOf(s)).collect(Collectors.joining(StringConstant.COMMA));
            String orgDeptName = orgDeptStaffList.stream().map(TbOrgDeptStaff::getSDeptName).collect(Collectors.joining(StringConstant.COMMA));
            String orgDeptPathName = orgDeptStaffList.stream().map(TbOrgDeptStaff::getSDeptPathName).collect(Collectors.joining(StringConstant.COMMA));

            List<TbOrgRoleMenu> tbOrgRoleMenuList = new ArrayList<>();
            List<TbOrgRoleStaff> tbOrgRoleStaffList = tbOrgRoleStaffMapper.findRoleListByStaffId(tbOrgStaff.getIStaffId());
            for(TbOrgRoleStaff tbOrgRoleStaff : tbOrgRoleStaffList){
                List<TbOrgRoleMenu> tbOrgRoleMenuTempList = tbOrgRoleMenuMapper.findMenuListByRolefId(tbOrgRoleStaff.getIRoleId());
                tbOrgRoleMenuList.addAll(tbOrgRoleMenuTempList);
            }
            List<TbOrgMenu> tbOrgMenuList = new ArrayList<>();
            for(TbOrgRoleMenu tbOrgRoleMenu : tbOrgRoleMenuList){
                List<TbOrgMenu> tbOrgMenuTempList = tbOrgMenuMapper.findMenuListByMenuId(tbOrgRoleMenu.getIMenuId());
                tbOrgMenuList.addAll(tbOrgMenuTempList);
            }
            String orgRoleId = tbOrgRoleStaffList.stream().map(TbOrgRoleStaff::getIRoleId).map(s ->String.valueOf(s)).collect(Collectors.joining(StringConstant.COMMA));
            String orgRoleName = tbOrgRoleStaffList.stream().map(TbOrgRoleStaff::getSRoleName).collect(Collectors.joining(StringConstant.COMMA));
            String orgPermissions = tbOrgMenuList.stream().map(TbOrgMenu::getSAuthCode).distinct().collect(Collectors.joining(StringConstant.COMMA));

            List<TbOrgPostStaff> postStaffList = tbOrgPostStaffMapper.findPostListByStaffId(tbOrgStaff.getIStaffId());
            String orgPostId = postStaffList.stream().map(TbOrgPostStaff::getIPostId).map(s ->String.valueOf(s)).collect(Collectors.joining(StringConstant.COMMA));
            String orgPostName = postStaffList.stream().map(TbOrgPostStaff::getSPostName).collect(Collectors.joining(StringConstant.COMMA));

            List<TbOrgJobStaff> jobStaffList = tbOrgJobStaffMapper.findJobListByStaffId(tbOrgStaff.getIStaffId());
            String orgJobId = jobStaffList.stream().map(TbOrgJobStaff::getIJobId).map(s ->String.valueOf(s)).collect(Collectors.joining(StringConstant.COMMA));
            String orgJobName = jobStaffList.stream().map(TbOrgJobStaff::getSJobName).collect(Collectors.joining(StringConstant.COMMA));

            String permissions = orgPermissions ;
            boolean notLocked = true;
            String password = tbOrgStaff.getSStaffPwd();
            String loginType = (String) httpServletRequest.getAttribute(ParamsConstant.LOGIN_TYPE);
            if (StringUtils.equals(loginType, SocialConstant.SOCIAL_LOGIN)) {
                password = passwordEncoder.encode(SocialConstant.getSocialLoginPassword());
            }

            List<GrantedAuthority> grantedAuthorities = AuthorityUtils.NO_AUTHORITIES;
            if (StringUtils.isNotBlank(permissions)) {
                grantedAuthorities = AuthorityUtils.commaSeparatedStringToAuthorityList(permissions);
            }
            HaiyuanAuthUser authUser = new HaiyuanAuthUser(tbOrgStaff.getSStaffName(), password, true, true, true, notLocked, grantedAuthorities);
            authUser.setUserId(tbOrgStaff.getIStaffId());
            authUser.setUserAcc(tbOrgStaff.getSStaffAcc());
            authUser.setUsername(tbOrgStaff.getSStaffName());
            authUser.setEmail(tbOrgStaff.getSStaffEmail());
            authUser.setMobile(tbOrgStaff.getSStaffMobile());
            if(tbOrgRoleStaffList.size() > 0) {
                TbOrgRoleStaff tbOrgRoleStaff = tbOrgRoleStaffList.get(0);
                authUser.setRoleId(Long.toString(tbOrgRoleStaff.getIRoleId()));
                authUser.setRoleName(tbOrgRoleStaff.getSRoleName());
            }

            authUser.setLoginId(""+uidGenerator.getUID());
            authUser.setFollowStaffId(followStaffId);
            authUser.setFollowStaffName(followStaffName);

            authUser.setAvatar("default.jpg");
            authUser.setRoleIds(orgRoleId);
            authUser.setRoleNames(orgRoleName);

            authUser.setJobIds(orgJobId);
            authUser.setJobNames(orgJobName);

            authUser.setPostIds(orgPostId);
            authUser.setPostNames(orgPostName);

            authUser.setDeptIds(orgDeptId);
            authUser.setDeptNames(orgDeptName);
            authUser.setDeptPathNames(orgDeptPathName);

            authUser.setProductId(productId);
            authUser.setProductIdList(productIdList);
            if(orgDeptStaffList.size() >0) {
                TbOrgDeptStaff tbOrgDeptStaff = orgDeptStaffList.get(0);

                TbOrgDomain tbOrgDomain = tbOrgDomainMapper.findByDomainId(tbOrgDeptStaff.getIDomainId());
                TbOrgDept tbOrgDept = tbOrgDeptMapper.findByDeptId(tbOrgDeptStaff.getIDeptId());
                String S_PATH_ID  = tbOrgDept.getSPathId();
                List<TbOrgDept> followDeptList = tbOrgDeptMapper.findByPathId(S_PATH_ID+"/%");
                if(null != followDeptList) {
                    String followDeptId = followDeptList.stream().map(TbOrgDept::getIDeptId).map(s -> String.valueOf(s)).collect(Collectors.joining(StringConstant.COMMA));
                    String followDeptName = followDeptList.stream().map(TbOrgDept::getSPathName).collect(Collectors.joining(StringConstant.COMMA));
                    authUser.setFollowDeptId(followDeptId);
                    authUser.setFollowDeptName(followDeptName);
                }
                authUser.setDeptPathId(S_PATH_ID);
                authUser.setDeptId(tbOrgDeptStaff.getIDeptId());
                authUser.setDeptName(tbOrgDeptStaff.getSDeptName());
                authUser.setDeptPathName(tbOrgDeptStaff.getSDeptPathName());
                authUser.setDeptCode(tbOrgDept.getSDeptCode());
                authUser.setDeptLeaderId(tbOrgDept.getILeaderId());
                authUser.setDeptLeaderName(tbOrgDept.getSLeaderName());

                authUser.setDomainId(tbOrgDomain.getIDomainId());
                authUser.setDomainCode(tbOrgDomain.getSDomainCode());
                authUser.setDomainName(tbOrgDomain.getSDomainName());
                authUser.setCreateParttion(tbOrgDomain.getCreatePartition());

                authUser.setLeaderId(tbOrgDeptStaff.getILeaderId());
                authUser.setLeaderName(tbOrgDeptStaff.getSLeaderName());
                authUser.setLeaderDeptId(tbOrgDeptStaff.getILeaderDeptId());
                authUser.setLeaderDeptName(tbOrgDeptStaff.getSDeptName());
                authUser.setLeaderDeptPathName(tbOrgDeptStaff.getSDeptPathName());
            }

            authUser.setTenantId(sysTenantModel.getTENANT_ID());
            authUser.setTenantName(sysTenantModel.getTENANT_NAME());
            authUser.setCreateParttion(sysTenantModel.getCREATE_PARTITION());
            authUser.setSalt("HY"+sysTenantModel.getSALT());

            authUser.setStartDate(sysTenantModel.getSTART_DATE());
            authUser.setEndDate(sysTenantModel.getEND_DATE());
            authUser.setAppId(sysTenantModel.getI_APP_ID());
            authUser.setAppName(sysTenantModel.getS_APP_NAME());
            authUser.setTenantAcc(sysTenantModel.getTENANT_ACC());
            authUser.setLayoutId(layoutId);
            initTenantDB(  authUser ,sysDsModel);
            insert (1,"登录成功",authUser);
            updateLoginSuccess(  authUser );
            return authUser;
        } else {
            insertFailue ( sysDsModel.getLog(),username,2, "账号不存在.");
            throw new UsernameNotFoundException("操作异常");
        }
    }

    private void updateLoginSuccess( HaiyuanAuthUser authUser ){
        Map<String,Object> data = new HashMap<>();
        data.put("dLoginTime", new Date());
        data.put("iStaffId", authUser.getUserId());
        DynamicDataSourceContextHolder.push(authUser.getOrgDsId());
        tbOrgStaffMapper.updateByLoginTime(data);
    }

    /**
     * 初始化系统租户信息
     * @param sysTenantModel 租户模型
     */
    private void initSysTenant(SysTenantModel sysTenantModel){
        TbSysTenant tbSysTenantEntity = tbSysTenantMapper.findByTenantId(sysTenantModel.getTENANT_ID());
        sysTenantModel.setTENANT_ACC(tbSysTenantEntity.getSAcc());
        sysTenantModel.setTENANT_NAME(tbSysTenantEntity.getSName());
        sysTenantModel.setSALT(tbSysTenantEntity.getSSalt());
        sysTenantModel.setEND_DATE(tbSysTenantEntity.getIEndDate());
        sysTenantModel.setSTART_DATE(tbSysTenantEntity.getIStartDate());

        sysTenantModel.setI_APP_ID(tbSysTenantEntity.getIAppId());
        sysTenantModel.setS_APP_NAME(tbSysTenantEntity.getSAppName());
    }

    private void getSysDsModel(String username,SysTenantModel sysTenantModel){
        DynamicDataSourceContextHolder.push(HaiyuanConstant.master);
        TbSysTenantUser tbSysTenantUserEntity = tbSysTenantUserMapper.findByAcc(username);
        if(ObjectUtil.isNull(tbSysTenantUserEntity) || ObjectUtil.isNull(tbSysTenantUserEntity.getSStaffAcc())){
            log.error("登录账号不存在."+username);
            sysTenantModel.setSysDsModel(null);
            return ;
        }
        SysDsModel sysDsModel = new SysDsModel();
        sysTenantModel.setSysDsModel(sysDsModel);
        sysTenantModel.setCREATE_PARTITION(tbSysTenantUserEntity.getCreatePartition());
        sysTenantModel.setTENANT_ID(tbSysTenantUserEntity.getTenantId());

        List<TbSysTenantRefDs> tbSysTenantRefDsEntityList = tbSysTenantRefDsMapper.findRefDsByTenantId(tbSysTenantUserEntity.getTenantId());
        for(TbSysTenantRefDs tbSysTenantRefDsEntity : tbSysTenantRefDsEntityList) {
            initSysDsModel(sysDsModel, tbSysTenantRefDsEntity);
        }
        initSysTenant( sysTenantModel);
    }

    private void initTenantDB(HaiyuanAuthUser authUser , SysDsModel sysDsModel){
        authUser.setDealDsId(sysDsModel.getDeal());
        authUser.setUiDsId(sysDsModel.getUi());
        authUser.setOrgDsId(sysDsModel.getOrg());
        authUser.setMetaDsId(sysDsModel.getMeta());
        authUser.setPrdDsId(sysDsModel.getPrd());
        authUser.setLogDsId(sysDsModel.getLog());
        authUser.setStatDsId(sysDsModel.getStat());
    }


    /**
     * 初始化数据源
     * @param sysDsModel
     * @param tbSysTenantRefDsEntity
     */
    private void initSysDsModel(SysDsModel sysDsModel, TbSysTenantRefDs tbSysTenantRefDsEntity){
        if(SysDsEnum.I_SYS_DS_SRC.META.getValue().intValue() == tbSysTenantRefDsEntity.getIRefDsSrc().intValue()){
            sysDsModel.setMeta(tbSysTenantRefDsEntity.getSRefDsId());
        }else  if(SysDsEnum.I_SYS_DS_SRC.DEAL.getValue().intValue() == tbSysTenantRefDsEntity.getIRefDsSrc().intValue()){
            sysDsModel.setDeal(tbSysTenantRefDsEntity.getSRefDsId());
        }else  if(SysDsEnum.I_SYS_DS_SRC.UI.getValue().intValue() == tbSysTenantRefDsEntity.getIRefDsSrc().intValue()){
            sysDsModel.setUi(tbSysTenantRefDsEntity.getSRefDsId());
        }else  if(SysDsEnum.I_SYS_DS_SRC.ORG.getValue().intValue() == tbSysTenantRefDsEntity.getIRefDsSrc().intValue()){
            sysDsModel.setOrg(tbSysTenantRefDsEntity.getSRefDsId());
        }else  if(SysDsEnum.I_SYS_DS_SRC.PRD.getValue().intValue() == tbSysTenantRefDsEntity.getIRefDsSrc().intValue()){
            sysDsModel.setPrd(tbSysTenantRefDsEntity.getSRefDsId());
        }else  if(SysDsEnum.I_SYS_DS_SRC.LOG.getValue().intValue() == tbSysTenantRefDsEntity.getIRefDsSrc().intValue()){
            sysDsModel.setLog(tbSysTenantRefDsEntity.getSRefDsId());
        }else  if(SysDsEnum.I_SYS_DS_SRC.STAT.getValue().intValue() == tbSysTenantRefDsEntity.getIRefDsSrc().intValue()){
            sysDsModel.setStat(tbSysTenantRefDsEntity.getSRefDsId());
        }
        else{
            //master数据源不允许重置
            log.error("异常配置数据:"+ JSON.toJSONString(tbSysTenantRefDsEntity));
        }
    }

    private  void insert ( Integer flag, String message,HaiyuanAuthUser currentUser){
        Integer src = 1;
        tbLogLoginService.insert(  currentUser,  src,  flag,  message);
    }


    private  void insertFailue (String dsId,String acc, Integer flag, String message){
        Integer src = 1;
        tbLogLoginService.insert(dsId,acc,src,flag,message);
    }
}
